//
//  basic_cal_matrix.c
//  linear_algebra
//
//  Created by zhangnan on 2025/3/25.
//

#include "basic_cal_matrix.h"

/**
 * 对两个双精度矩阵进行加法运算。
 * 
 * @param a 第一个矩阵。
 * @param b 第二个矩阵。
 * @return 指向结果矩阵的指针，如果矩阵尺寸不匹配则返回 NULL。
 */
MATRIX_DOUBLE_TYPE* add_double(MATRIX_DOUBLE_TYPE *a, MATRIX_DOUBLE_TYPE *b)
{
    // 检查两个矩阵的维度是否匹配
    if(a->cols != b->cols || a->rows != b->rows)
    {
        printf("错误：矩阵尺寸不匹配\n");
        return NULL;
    }else{
        // 创建一个新的矩阵用于存储结果
        MATRIX_DOUBLE_TYPE *c = create_double_matrix(a->rows, a->cols);
        // 遍历每个元素并进行加法运算
        for(int i = 0; i < a->rows; i++)
        {
            for(int j = 0; j < a->cols; j++)
            {
                c->array[i*a->cols+j] = a->array[i*a->cols+j] + b->array[i*a->cols+j];
            }
        }
        return c;
    }
}

/**
 * 对两个双精度矩阵进行减法运算。
 * 
 * @param a 第一个矩阵。
 * @param b 第二个矩阵。
 * @return 指向结果矩阵的指针，如果矩阵尺寸不匹配则返回 NULL。
 */
MATRIX_DOUBLE_TYPE* sub_double(MATRIX_DOUBLE_TYPE *a, MATRIX_DOUBLE_TYPE *b)
{
    // 检查两个矩阵的维度是否匹配
    if(a->cols != b->cols || a->rows != b->rows)
    {
        printf("错误：矩阵尺寸不匹配\n");
        return NULL;
    }else{
        // 创建一个新的矩阵用于存储结果
        MATRIX_DOUBLE_TYPE *c = create_double_matrix(a->rows, a->cols);
        // 遍历每个元素并进行减法运算
        for(int i = 0; i < a->rows; i++)
        {
            for(int j = 0; j < a->cols; j++){
                c->array[i*a->cols+j] = a->array[i*a->cols+j] - b->array[i*a->cols+j];
            }
        }
        return c;
    }
}

/**
 * 对两个双精度矩阵进行乘法运算。
 * 
 * @param a 第一个矩阵。
 * @param b 第二个矩阵。
 * @return 指向结果矩阵的指针，如果矩阵维度不符合乘法条件则返回 NULL。
 */
MATRIX_DOUBLE_TYPE* mul_double(MATRIX_DOUBLE_TYPE *a, MATRIX_DOUBLE_TYPE *b)
{
    // 检查第一个矩阵的列数是否等于第二个矩阵的行数
    if(a->cols != b->rows)
    {
        printf("错误：矩阵尺寸不匹配\n");
        return NULL;
    }else{
        // 创建一个新的矩阵用于存储结果
        MATRIX_DOUBLE_TYPE *c = create_double_matrix(a->rows, b->cols);
        // 执行矩阵乘法
        for(int i = 0; i < a->rows; i++)
        {
            for(int j = 0; j < b->cols; j++)
            {
                for(int k = 0; k < a->cols; k++)
                {
                    c->array[i*b->cols+j] += a->array[i*a->cols+k] * b->array[k*b->cols+j];
                }
            }
        }
        return c;
    }
}

/**
 * 将双精度矩阵与标量相乘。
 * 
 * @param a 矩阵。
 * @param b 标量。
 * @return 指向结果矩阵的指针。
 */
MATRIX_DOUBLE_TYPE* mul_double_scalar(MATRIX_DOUBLE_TYPE *a, double b)
{
    // 创建一个新的矩阵用于存储结果
    MATRIX_DOUBLE_TYPE *c = create_double_matrix(a->rows, a->cols);
    // 将矩阵的每个元素与标量相乘
    for(int i = 0; i < a->rows; i++)
    {
        for(int j = 0; j < a->cols; j++)
        {
            c->array[i*a->cols+j] = a->array[i*a->cols+j] * b;
        }
    }
    return c;
}

/**
 * 对两个整数矩阵进行加法运算。
 * 
 * @param a 第一个矩阵。
 * @param b 第二个矩阵。
 * @return 指向结果矩阵的指针，如果矩阵尺寸不匹配则返回 NULL。
 */
MATRIX_INT_TYPE* add_int(MATRIX_INT_TYPE *a, MATRIX_INT_TYPE *b)
{
    // 检查两个矩阵的维度是否匹配
    if(a->cols != b->cols || a->rows != b->rows)
    {
        printf("错误：矩阵尺寸不匹配\n");
        return NULL;
    }else{
        // 创建一个新的矩阵用于存储结果
        MATRIX_INT_TYPE *c = create_int_matrix(a->rows, a->cols);
        // 遍历每个元素并进行加法运算
        for(int i = 0; i < a->rows; i++)
        {
            for(int j = 0; j < a->cols; j++)
            {
                c->array[i*a->cols+j] = a->array[i*a->cols+j] + b->array[i*a->cols+j];
            }
        }
        return c;
    }
}

/**
 * 对两个整数矩阵进行减法运算。
 * 
 * @param a 第一个矩阵。
 * @param b 第二个矩阵。
 * @return 指向结果矩阵的指针，如果矩阵尺寸不匹配则返回 NULL。
 */
MATRIX_INT_TYPE* sub_int(MATRIX_INT_TYPE *a, MATRIX_INT_TYPE *b)
{
    // 检查两个矩阵的维度是否匹配
    if(a->cols != b->cols || a->rows != b->rows)
    {
        printf("错误：矩阵尺寸不匹配\n");
        return NULL;
    }else{
        // 创建一个新的矩阵用于存储结果
        MATRIX_INT_TYPE *c = create_int_matrix(a->rows, a->cols);
        // 遍历每个元素并进行减法运算
        for(int i = 0; i < a->rows; i++)
        {
            for(int j = 0; j < a->cols; j++){
                c->array[i*a->cols+j] = a->array[i*a->cols+j] - b->array[i*a->cols+j];
            }
        }
        return c;
    }
}

/**
 * 对两个整数矩阵进行乘法运算。
 * 
 * @param a 第一个矩阵。
 * @param b 第二个矩阵。
 * @return 指向结果矩阵的指针，如果矩阵维度不符合乘法条件则返回 NULL。
 */
MATRIX_INT_TYPE* mul_int(MATRIX_INT_TYPE *a, MATRIX_INT_TYPE *b)
{
    // 检查第一个矩阵的列数是否等于第二个矩阵的行数
    if(a->cols != b->rows)
    {
        printf("错误：矩阵尺寸不匹配\n");
        return NULL;
    }else{
        // 创建一个新的矩阵用于存储结果
        MATRIX_INT_TYPE *c = create_int_matrix(a->rows, b->cols);
        // 执行矩阵乘法
        for(int i = 0; i < a->rows; i++)
        {
            for(int j = 0; j < b->cols; j++)
            {
                for(int k = 0; k < a->cols; k++)
                {
                    c->array[i*b->cols+j] += a->array[i*a->cols+k] * b->array[k*b->cols+j];
                }
            }
        }
        return c;
    }
}

/**
 * 将整数矩阵与标量相乘。
 * 
 * @param a 矩阵。
 * @param b 标量。
 * @return 指向结果矩阵的指针。
 */
MATRIX_INT_TYPE* mul_int_scalar(MATRIX_INT_TYPE *a, int b)
{
    // 创建一个新的矩阵用于存储结果
    MATRIX_INT_TYPE *c = create_int_matrix(a->rows, a->cols);
    // 将矩阵的每个元素与标量相乘
    for(int i = 0; i < a->rows; i++)
    {
        for(int j = 0; j < a->cols; j++)
        {
            c->array[i*a->cols+j] = a->array[i*a->cols+j] * b;
        }
    }
    return c;
}

/**
 * 转置双精度矩阵。
 * 
 * @param a 指向要转置的双精度矩阵的指针。
 * @return 指向转置后的双精度矩阵的指针。
 * 
 * 此函数创建一个新矩阵，并通过交换输入矩阵的行和列来执行转置操作。
 * 它不会修改原始矩阵，而是返回一个新的转置矩阵。
 */
MATRIX_DOUBLE_TYPE* transpose_double(MATRIX_DOUBLE_TYPE *a)
{
    // 创建一个新的矩阵用于存储结果
    MATRIX_DOUBLE_TYPE *c = create_double_matrix(a->cols, a->rows);
    // 转置矩阵
    for(int i = 0; i < a->rows; i++)
    {
        for(int j = 0; j < a->cols; j++)
        {
            c->array[j*a->rows+i] = a->array[i*a->cols+j];
        }
    }
    return c;
}

/**
 * 转置整数矩阵。
 * 
 * @param a 指向要转置的整数矩阵的指针。
 * @return 指向转置后的整数矩阵的指针。
 * 
 * 此函数创建一个新矩阵，并通过交换输入矩阵的行和列来执行转置操作。
 * 它不会修改原始矩阵，而是返回一个新的转置矩阵。
 */
MATRIX_INT_TYPE* transpose_int(MATRIX_INT_TYPE *a)
{
    // 创建一个新的矩阵用于存储结果
    MATRIX_INT_TYPE *c = create_int_matrix(a->cols, a->rows);
    // 转置矩阵
    for(int i = 0; i < a->rows; i++)
    {
        for(int j = 0; j < a->cols; j++)
        {
            c->array[j*a->rows+i] = a->array[i*a->cols+j];
        }
    }
    return c;
}